/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.quickorm.dialect;

import com.quickorm.entity.DBNull;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 *
 * @author aaa
 */
public abstract class Dialect {

    public String DATE_FROMATE = "yyyy-MM-dd HH:mm:ss";

    /**
     * 得到在数据库中代表Null的字符串
     *
     * @return
     */
    public abstract String getDBNullString();

    /**
     * 获取标识符的前缀
     *
     * @return
     */
    public abstract String getIdentifierPrefix();

    /**
     * 获取标识符的后缀
     *
     * @return
     */
    public abstract String getIdentifierSuffix();

    /**
     * 获取值的前缀
     *
     * @return
     */
    public abstract String getValuePrefix();

    /**
     * 获取值的后缀
     *
     * @return
     */
    public abstract String getValueSuffix();

    /**
     * 得到要替换的特殊字符串Map
     *
     * @return
     */
    public abstract Map<String, String> getReplaceSpecialStringMap();

    /**
     * 是否支持分布查询SQL优化
     *
     * @return
     */
    public abstract boolean isSupportPagedQuerySqlOptimize();

    /**
     * 得到获取记录数据数量SQL
     *
     * @param sql
     * @return
     */
    public abstract String getRecordCountSql(String sql);

    /**
     * 得到分布查询SQL
     *
     * @param sql 原始SQL
     * @param offset 偏移量
     * @param limit 记录数限制
     * @return
     */
    public abstract String getPagedQuerySql(String sql, int offset, int limit);

    /**
     * 替换包含特殊SQL字符字符串为普通字符串
     *
     * @param content
     * @return
     */
    public String replaceIncludeSpecialSqlCharStringToNormalString(String content) {
        String tmpStr = content;
        Map<String, String> map = getReplaceSpecialStringMap();
        for (String key : map.keySet()) {
            if (tmpStr.contains(key)) {
                tmpStr = tmpStr.replace(key, map.get(key));
            }
        }
        return tmpStr;
    }

    /**
     * 添加标识符的分隔字符串
     *
     * @param content
     * @return
     */
    public String addIdentifierSeparatingChar(String content) {
        return this.getIdentifierPrefix() + content + this.getIdentifierSuffix();
    }

    /**
     * 得到最终的SQL语句
     *
     * @param sql 模板SQL
     * @param argumentList 参数列表
     * @param conditionArguemntMap 条件Map
     * @param sqlSuffix SQL后缀(主要是排序用)
     * @return
     */
    public String getFinalSql(String sql, List<Object> argumentList, Map<String, Object> conditionArguemntMap, String sqlSuffix) {
        //全部参数集合
        List<Object> allArgumentList = new ArrayList<Object>();
        //最终SQL字符串构造器
        StringBuilder sbFinalSql = new StringBuilder(sql);


        //如果有参数列表
        if (argumentList != null && !argumentList.isEmpty()) {
            //先加入传入的参数列表
            allArgumentList.addAll(argumentList);
        }

        //如果有查询条件
        if (conditionArguemntMap != null && !conditionArguemntMap.isEmpty()) {
            //要用到的条件列表
            List<String> usedConditionList = new LinkedList<String>();
            //然后加入要用到的条件的参数
            for (String conditionString : conditionArguemntMap.keySet()) {
                Object arg = conditionArguemntMap.get(conditionString);
                if (arg != null) {
                    usedConditionList.add(conditionString);
                    allArgumentList.add(arg);
                }
            }
            //拼装SQL语句的条件部分
            if (!usedConditionList.isEmpty()) {
                sbFinalSql.append(" WHERE");
                for (int i = 0; i <= usedConditionList.size() - 1; i++) {
                    if (i != 0) {
                        sbFinalSql.append(" AND");
                    }
                    sbFinalSql.append(" ").append(usedConditionList.get(i));
                }
            }
        }

        //SQL后缀
        if (sqlSuffix != null && !"".equals(sqlSuffix)) {
            sbFinalSql.append(" ").append(sqlSuffix);
        }
        //设置参数
        sbFinalSql = mergeSqlAndParameters(sbFinalSql, allArgumentList);

        //返回
        return sbFinalSql.toString();
    }

    //合并SQL语句与参数
    private StringBuilder mergeSqlAndParameters(StringBuilder sbFinalSql, List<Object> argumentList) {
        //扫描参数占位符
        List<Integer> parameterPlaceholderIndexList = new ArrayList<Integer>();
        List<String> parameterPlaceholderContentList = new ArrayList<String>();

        for (int i = 0; i <= sbFinalSql.length() - 1; i++) {
            char startChar = sbFinalSql.charAt(i);
            //如果是问号占位符
            if (startChar == '?') {
                parameterPlaceholderIndexList.add(i);
                parameterPlaceholderContentList.add("?");
            }
        }

        //从后向前替换参数占位符为参数的SQL字符串形式
        for (int i = parameterPlaceholderIndexList.size() - 1; i >= 0; i--) {
            int currentPlaceHolderIndex = parameterPlaceholderIndexList.get(i);
            String currentPlaceHolderContent = parameterPlaceholderContentList.get(i);
            //如果是问号占位符
            if ("?".equals(currentPlaceHolderContent)) {
                Object currentParameter = argumentList.get(i);
                String currentParameterString = getParameterStringInSql(currentParameter);

                //如果问号占位符后面是百分号
                if ((sbFinalSql.length() - 1 >= currentPlaceHolderIndex + 1) && (sbFinalSql.charAt(currentPlaceHolderIndex + 1) == '%')) {
                    String tmpString = currentParameterString.substring(0, currentParameterString.length() - 1) + "%" + currentParameterString.charAt(currentParameterString.length() - 1);
                    currentParameterString = tmpString;
                    sbFinalSql.deleteCharAt(currentPlaceHolderIndex + 1);
                }
                
                //如果问号占位符前面是百分号
                if ((currentPlaceHolderIndex - 1 > 0) && (sbFinalSql.charAt(currentPlaceHolderIndex - 1) == '%')) {
                    String tmpString = currentParameterString.charAt(0) + "%" + currentParameterString.substring(1);
                    currentParameterString = tmpString;
                    sbFinalSql.deleteCharAt(currentPlaceHolderIndex - 1);
                    currentPlaceHolderIndex--;
                }
                
                //准备替换
                sbFinalSql.replace(currentPlaceHolderIndex, currentPlaceHolderIndex + currentPlaceHolderContent.length(), currentParameterString);
            }
        }

        return sbFinalSql;
    }

    public String getParameterStringInSql(Object parameter) {
        String parameterString = "";

        //是否应该替换数据库特殊字符
        boolean isShouldReplaceSpecialSqlChar = true;
        //是否应该在字符串两边加分隔符
        boolean isShouldAddStringSeparatingChar = false;

        //得到字符串表示形式

        //如果是字符串
        if (String.class.isInstance(parameter)) {
            parameterString = (String) parameter;
            isShouldReplaceSpecialSqlChar = true;
            isShouldAddStringSeparatingChar = true;
        } //如果是数字
        else if (Number.class.isInstance(parameter)) {
            parameterString = parameter.toString();
            isShouldReplaceSpecialSqlChar = false;
            isShouldAddStringSeparatingChar = false;
        } //如果是日期
        else if (Date.class.isInstance(parameter)) {
            SimpleDateFormat dateFm = new SimpleDateFormat(DATE_FROMATE);
            parameterString = dateFm.format((Date) parameter);
            isShouldReplaceSpecialSqlChar = true;
            isShouldAddStringSeparatingChar = true;
        } //如果是布尔类型
        else if (Boolean.class.isInstance(parameter)) {
            if ((Boolean) parameter) {
                parameterString = "1";
            } else {
                parameterString = "0";
            }
            isShouldReplaceSpecialSqlChar = false;
            isShouldAddStringSeparatingChar = false;
        } //如果是数据库空
        else if (DBNull.class.isInstance(parameter)) {
            parameterString = getDBNullString();
            isShouldReplaceSpecialSqlChar = false;
            isShouldAddStringSeparatingChar = false;
        } else {
            parameterString = parameter.toString();
            isShouldReplaceSpecialSqlChar = true;
            isShouldAddStringSeparatingChar = true;
        }
        //替换SQL特殊符号
        if (isShouldReplaceSpecialSqlChar) {
            parameterString = replaceIncludeSpecialSqlCharStringToNormalString(parameterString);
        }
        //是否添加字符串分隔符
        if (isShouldAddStringSeparatingChar) {
            parameterString = getValuePrefix() + parameterString + getValueSuffix();;
        }
        return parameterString;
    }
}
